package org.ru.mse10.cvis.web.validator;

import java.util.ArrayList;
import java.util.regex.Pattern;

/**
 * The Class UrlFilter.
 */
public class UrlFilter {

	/** The include. */
	private ArrayList<Pattern> include = new ArrayList<Pattern>();

	/** The exclude. */
	private ArrayList<Pattern> exclude = new ArrayList<Pattern>();

	/**
	 * Instantiates a new url filter.
	 */
	public UrlFilter() {

	}

	/**
	 * Include the wildcard(*) built pattern.
	 * 
	 * @param pattern
	 *            the pattern
	 * @return the url filter
	 */
	public UrlFilter include(String pattern) {
		include.add(generateExpression(pattern));
		return this;
	}

	/**
	 * Exclude the wildcard(*) built pattern.
	 * 
	 * @param pattern
	 *            the pattern
	 * @return the url filter
	 */
	public UrlFilter exclude(String pattern) {
		exclude.add(generateExpression(pattern));
		return this;
	}

	/**
	 * Checks to see if uri matches at least ONE inclusion filter and doesn't
	 * match ANY exclusion filters.
	 * 
	 * @param uri
	 *            the uri
	 * @return true, if successful
	 */
	public boolean matches(String uri) {
		boolean match = false;

		// check inclusions
		for (Pattern pattern : include) {
			match = match || pattern.matcher(uri).matches();
		}

		if (!match)
			return false;

		// check exclusions
		for (Pattern pattern : exclude) {
			match = match && !pattern.matcher(uri).matches();
		}
		return match;
	}

	/** regular expression special character. */
	private static char[] specialChars = { '[', '\\', '^', '$', '.', '|', '?',
			'*', '+', '(', ')' };

	/**
	 * Generate expression.
	 * 
	 * @param input
	 *            the input
	 * @return the pattern
	 */
	private static Pattern generateExpression(String input) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < input.length(); i++) {
			char letter = input.charAt(i);
			if (letter == '*') {
				sb.append(".*");
			} else if (contains(specialChars, letter)) {
				sb.append("\\" + letter);
			} else {
				sb.append(letter);
			}
		}
		return Pattern.compile(sb.toString());
	}

	/**
	 * Contains.
	 * 
	 * @param array
	 *            the array
	 * @param value
	 *            the value
	 * @return true, if successful
	 */
	private static boolean contains(char[] array, char value) {
		if (array == null || array.length == 0) {
			return false;
		}

		for (int i = 0; i < array.length; i++) {
			char o = array[i];
			if (o == value) {
				return true;
			}
		}

		return false;
	}
}